#pragma once

#include "vec2.h"
#include "../arch/avx.h"

OPEN_JLIB_NS


struct Box2 {

  f32v4 p;

  inline Box2 () noexcept = default;
  inline Box2 (f32v4 p) noexcept : p(p) {
  }
  inline Box2 (f32 minx, f32 miny, f32 maxx, f32 maxy) {
    p = avx_vunpcklps<f32v4>(minx, miny);
    p = avx_vinsertps<0x20, f32v4>(p, maxx);
    p = avx_vinsertps<0x30, f32v4>(p, maxy);
  }
  inline Box2 (Vec2 min, Vec2 max) {
    p = avx_vunpcklpd<f32v4>(min.p, max.p);
  }
  inline Box2 (const f32* m) noexcept {
    p = avx_vlddqu<f32v4>(m);
  }


  inline Box2& operator&= (Box2 v) noexcept {
    auto min = avx_vminps<f32v4>(p, v.p);
    auto max = avx_vmaxps<f32v4>(p, v.p);
    p = avx_vblendpd<0x1, f32v4>(min, max);
    return *this;
  }
  inline Box2& operator|= (Box2 v) noexcept {
    auto min = avx_vminps<f32v4>(p, v.p);
    auto max = avx_vmaxps<f32v4>(p, v.p);
    p = avx_vblendpd<0x2, f32v4>(min, max);
    return *this;
  }


  inline Box2 operator& (Box2 v) const noexcept {
    auto min = avx_vminps<f32v4>(p, v.p);
    auto max = avx_vmaxps<f32v4>(p, v.p);
    return avx_vblendpd<0x1, f32v4>(min, max);
  }
  inline Box2 operator| (Box2 v) const noexcept {
    auto min = avx_vminps<f32v4>(p, v.p);
    auto max = avx_vmaxps<f32v4>(p, v.p);
    return avx_vblendpd<0x2, f32v4>(min, max);
  }


  inline Vec2 operator~ () const noexcept {
    auto h = avx_vshufpd<0x3, f64>(p, p);
    return avx_vsubps<f64>(h, p);
  }


  inline f32 x () const noexcept {
    return p[0];
  }
  inline f32 y () const noexcept {
    return p[1];
  }
  inline f32 X () const noexcept {
    return p[2];
  }
  inline f32 Y () const noexcept {
    return p[3];
  }


  inline Vec2 xy () const noexcept {
    return avx_cast<f64>(p);
  }
  inline Vec2 xY () const noexcept {
    return avx_vshufps<0xC, f64>(p, p);
  }
  inline Vec2 Xy () const noexcept {
    return avx_vshufps<0x6, f64>(p, p);
  }
  inline Vec2 XY () const noexcept {
    return avx_vshufps<0xE, f64>(p, p);
  }


  inline bool contains (Vec2 v) const noexcept {
    auto a = avx_vshufpd<0x0, f32v4>(p, v.p);
    auto b = avx_vshufpd<0x2, f32v4>(v.p, p);
    auto m = avx_vcmpps<avx::NLE_UQ, f32v4>(a, b);
    return avx_vmovmskps_<u32>(m) == 0;
  }
  inline bool contains (Box2 v) const noexcept {
    auto a = avx_vshufpd<0x2, f32v4>(p, v.p);
    auto b = avx_vshufpd<0x2, f32v4>(v.p, p);
    auto m = avx_vcmpps<avx::NLE_UQ, f32v4>(a, b);
    return avx_vmovmskps_<u32>(m) == 0;
  }
  inline bool intersect (Box2 v) const noexcept {
    auto a = avx_vunpcklpd<f32v4>(p, v.p);
    auto b = avx_vunpckhpd<f32v4>(v.p, p);
    auto m = avx_vcmpps<avx::NLT_UQ, f32v4>(a, b);
    return avx_vmovmskps_<u32>(m) == 0;
  }
};


CLOSE_JLIB_NS